/***************************************************************************
 创建者: 华磊
 开始时间: 2020.8.14
 copyright: (C) 华友高科
 修改说明: (每次有修改就添加一条，带有 修改人，修改时间，修改描述)
 example (1) hualei 2020.5.8 类的具体实现代码编写

 ***************************************************************************/
#include "robotio.h"

#include <QDebug>

//#include "messagelog.h"


RobotIo::RobotIo(QString configFilePathIn)
{

    configFilePath=configFilePathIn;
    isInitialOk=false;
#if D_IO_USE_VECTOR

#else
    diCount=0;//逻辑层IO
    doCount=0;//逻辑层IO
    siCount=0;//逻辑层IO
    soCount=0;//逻辑层IO
    aiCount=0;//逻辑层IO
    aoCount=0;//逻辑层IO

    memset( ioDi, 0, sizeof(ioDi) );
    memset( ioDo, 0, sizeof(ioDo) );
    memset( ioSi, 0, sizeof(ioSi) );
    memset( ioSo, 0, sizeof(ioSo) );
    memset( ioAi, 0, sizeof(ioAi) );
    memset( ioAo, 0, sizeof(ioAo) );
#endif
}

int RobotIo::getEmergencyDi(bool &emStop1,bool &emStop2)
{

    if(EMSTOP1_INDEX>=diCount || EMSTOP2_INDEX>=diCount)
        return -1;
    emStop1= ioSi[EMSTOP1_INDEX];
    emStop2= ioSi[EMSTOP2_INDEX];
    return 1;
}

int RobotIo::getServoOnDi(bool &servoOnDi)
{
     if(SERVOON_INDEX>=diCount )
        return -1;
    servoOnDi= ioSi[SERVOON_INDEX];
    return 1;
}

unsigned short RobotIo::getDi_short(int shortIndex)
{
   if(shortIndex<0)
   {
       return 0;
   }
   unsigned short tmpDiList;
   for(int i=0;i<16;i++)
   {
       tmpDiList=tmpDiList<<1;
       tmpDiList=tmpDiList|ioDi[(shortIndex+1)*16-1-i];
   }
   return tmpDiList;
}

unsigned short RobotIo::getDo_short(int shortIndex)
{
    if(shortIndex<0)
    {
        return 0;
    }
    unsigned short tmpDoList;
    for(int i=0;i<16;i++)
    {
        tmpDoList=tmpDoList<<1;
        tmpDoList=tmpDoList|ioDo[(shortIndex+1)*16-1-i];
    }
    return tmpDoList;
}

bool RobotIo::getDi(int index)
{
    if(index>=diCount || index<0)
        return false;
    return ioDi[index];
}

bool RobotIo::getDo(int index)
{
    if(index>=diCount || index<0)
        return false;
    return ioDo[index];
}

bool RobotIo::setDi(int index, bool valueIn)
{
    if(index>=diCount || index<0)
        return false;
    ioDi[index]=valueIn;
    return true;
}

int RobotIo::setDoVector(unsigned short doListIn, unsigned short doValidMask)
{
//    qDebug()<<"RobotIo::setDoVector"<<doListIn<<doValidMask;
    for(int i=0;i<16;i++)
    {
        if(1== (doValidMask&1))
        {
            ioDo[i]=doListIn&1;
//            qDebug()<<"i"<<i<<"value"<<ioDo[i];
        }
        doValidMask=doValidMask>>1;
        doListIn=doListIn>>1;

    }
    return 1;
}


bool RobotIo::getSi(int index)
{
    if(index>=siCount|| index<0)
        return false;
    return ioSi[index];
}

bool RobotIo::getSo(int index)
{
    if(index>=soCount|| index<0)
        return false;
    return ioSo[index];
}

double RobotIo::getAi(int index)
{
    if(index>=aiCount|| index<0)
        return false;
    return ioAi[index];
}

bool RobotIo::setDo(int index, bool val)
{
    if(index>=doCount|| index<0){
//        printf("false setdo; %d\n",doCount);
        return false;
    }
//    printf("RobotIo::setDo index %d,val %d\n",index,val);
    ioDo[index]=val;
    return true;
}

bool RobotIo::setSo(int index, bool val)
{
    if(index>=soCount|| index<0){
        //            printf("false setso; %d\n",soCount);
        return false;
    }
    ioSo[index]=val;
    return true;
}

bool RobotIo::setAo(int index, double val)
{
    if(index>=aoCount|| index<0)
        return false;
    ioAo[index]=val;
    return true;
}

void RobotIo::updateLv3(std::vector<bool> &_ioDi, std::vector<bool> &_ioDo, std::vector<bool> &_ioSi,
                        std::vector<bool> &_ioSo, std::vector<double> &_ioAi, std::vector<double> &_ioAo)
{
    _ioDi.resize( diCount );
    _ioDo.resize( doCount );
    _ioSi.resize( siCount );
    _ioSo.resize( soCount );
    _ioAi.resize( aiCount );
    _ioAo.resize( aoCount );

    for(int i=0;i<diCount;i++){
        _ioDi[i]=ioDi[i];
    }
    for(int i=0;i<aiCount;i++){
        _ioAi[i]=ioAi[i];
    }
    for(int i=0;i<siCount;i++){
        _ioSi[i]=ioSi[i];
    }
    for(int i=0;i<doCount;i++){
        _ioDo[i]=ioDo[i];
    }
    for(int i=0;i<soCount;i++){
        _ioSo[i]=ioSo[i];
    }
    for(int i=0;i<aoCount;i++){
        _ioAo[i]=ioAo[i];
    }
}



#if D_IO_USE_VECTOR

bool RobotIo::readXmlConfig(  QString filepath )
{

    bool ok=openXml(filepath, QFile::ReadOnly|QFile::Text );
    if(!ok){
        qDebug()<<"ERROR: openXml :"<<ok<< filepath;
        return false;
    }

    int  doMax =0 ;
    int  diMax =0 ;
    int  aoMax =0 ;
    int  aiMax =0 ;
    int  soMax =0 ;
    int  siMax =0 ;
    int  count=0;
    QDomNodeList devNodes = m_root.childNodes();
    allIoMap.resize( devNodes.size() ) ;
    for(int i=0;i<devNodes.size();i++)
    {
        QDomNode devND =  devNodes.at(i);
        if( devND.nodeName() .indexOf("#comment")>=0){
            continue;
        }

        IoMap tmpIomap;
        tmpIomap.nodeId=  devND.toElement().attribute("nodeId" ).toUInt();
        tmpIomap.valueType=  devND.toElement().attribute("valueType" ).toUInt();
        int __index = devND.toElement().attribute("logicValueIndex" ).toUInt();
        if( __index <1 ){
             tmpIomap.logicValueIndex=0;
           // addMsg(ENUM_MSG_WARNING, "RobotIo", "RobotIo", 5001,  robotId ,   tmpIomap.nodeId,   tmpIomap.valueType, __index );
            closeXml();
            return false;
        }else{
            tmpIomap.logicValueIndex= __index-1;
        }
       __index =  devND.toElement().attribute("deviceValueIndex" ).toUInt() ;
       if( __index <1 ){
           tmpIomap.deviceValueIndex=0;
          // addMsg(ENUM_MSG_WARNING, "RobotIo", "RobotIo", 5001,  robotId ,   tmpIomap.nodeId,   tmpIomap.valueType, __index );
           closeXml();
           return false;
       }else{
           tmpIomap.deviceValueIndex=  __index-1;
       }

        tmpIomap.devType=  devND.toElement().attribute("devType" ).toUInt();
        tmpIomap.note =  devND.firstChild().nodeValue();

        if(ok &&   tmpIomap.valueType != E_IoValueType_NULL )
        {
            allIoMap[ count ] = tmpIomap;
            count++;
        }
    }
    closeXml();

    allIoMap.resize( count );
    for(int i=0;i<count ;i++)
    {
        switch( allIoMap[i].valueType )
        {
        case    E_IoValueType_DI:
            ioDiMap.append( &allIoMap[i] );
            if( diMax<=allIoMap[i].logicValueIndex ){
                diMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        case       E_IoValueType_DO:
            ioDoMap.append( &allIoMap[i] );
            if( doMax<=allIoMap[i].logicValueIndex ){
                doMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        case      E_IoValueType_AI:
            ioAiMap.append( &allIoMap[i] );
            if( aiMax<=allIoMap[i].logicValueIndex ){
                aiMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        case     E_IoValueType_AO:
            ioAoMap.append( &allIoMap[i] );
            if( aoMax<=allIoMap[i].logicValueIndex ){
                aoMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        case         E_IoValueType_SI:
            ioSiMap.append( &allIoMap[i] );
            if( siMax<=allIoMap[i].logicValueIndex ){
                siMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        case      E_IoValueType_SO:
            ioSoMap.append( &allIoMap[i] );
            if( soMax<=allIoMap[i].logicValueIndex ){
                soMax=allIoMap[i].logicValueIndex+1;
            }
            break;
        }
    }

    ioDi.resize( diMax );
    ioDo.resize( doMax );
    ioSi.resize( siMax );
    ioSo.resize( soMax );
    ioAi.resize( aiMax );
    ioAo.resize( aoMax );

    qDebug()<<"\n iomap.xml=="<< diMax<<doMax <<siMax<<soMax <<aiMax <<aoMax;
    return true;
}

#else

bool RobotIo::isInitialStatus()
{
    return isInitialOk;
}

int RobotIo::get_All_IO_NamesInfo( struct IOMapNamesInfo &nameOut)
{
     QFile *file = new QFile();
     file->setFileName(configFilePath);

     if(file->isOpen())
     {
         qDebug()<<"==========XmlParse===file already open======"<<"\n\n\n";
         file->reset();
         file->close();
     }
     if(!file->open(QFile::ReadWrite | QFile::Text))
     {
         //消息预留
         //打开ｘｍｌ文件失败
         qDebug() << QObject::tr("error::ParserXML->OpenXmlFile->file.open->%s\n") << configFilePath;
         return -1;
     }

     QDomDocument m_doc;
     // 设置内容
     if(!m_doc.setContent(file))
     {
         //消息预留
         //ｘｍｌ文件格式不正确
          qDebug() << QObject::tr("error::ParserXML->OpenXmlFile->doc.setContent\n");
          file->close();
          return -1;
     }
     file->close();
//     file->reset();

    QDomElement root = m_doc.documentElement();
    if("IoDataMap" == root.tagName())
    {
        // 获取子节点列表
        QDomNodeList lists = root.childNodes();

        for(int i = 0;i<lists.count();i++)
        {
            // 获取其中一个子节点
            QDomNode ioData = lists.at(i);
            // 获取子节点元素
            QDomElement ele = ioData.toElement();

            // 获取子节点元素属性值
            /********* DI *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_DI)
            {
                nameOut.diNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }

            /********* DO *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_DO)
            {
                nameOut.doNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }

            /********* AI *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_AI)
            {
                nameOut.aiNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }

            /********* AO *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_AO)
            {
                nameOut.aoNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }

            /********* SI *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_SI)
            {
                nameOut.siNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }

            /********* SO *********/
            if(ele.attribute("valueType").toInt() == E_IoValueType_SO)
            {
                nameOut.soNamesInfo.push_back(ele.firstChild().nodeValue().toStdString());
            }
        }
    }
    return 0;
}

int RobotIo::set_IO_NameInfo( int IOValueTypeIn, int logicValueIndexIn, std::string nameIn, int &returnFlag)
{
    QFile IOMapFile(configFilePath);

    if(IOMapFile.isOpen())
    {
        IOMapFile.reset();
        IOMapFile.close();
    }
    // 读写方式打开文件
    if(!IOMapFile.open(QFile::ReadWrite | QFile::Text))
    {
        // 打开失败
        qDebug() << "GlobalManager::set_IO_NameInfo Open File:" << configFilePath << " ======= Failed!";
        returnFlag = -1;
        return -1;
    }

    QDomDocument iomap_Doc;
    // 设置内容
    if(!iomap_Doc.setContent(&IOMapFile))
    {
        // 设置文件内容失败
        qDebug() << "GlobalManager::set_IO_NameInfo Open File:" << configFilePath << " ======= setContent Failed!";
        returnFlag =-1;
        IOMapFile.close();
        return -1;
    }
    // 文件一定要关闭,否则会有操作失败
    IOMapFile.close();

    // 读取解析文件
    if(iomap_Doc.documentElement().tagName() == "IoDataMap")
    {
        // 获取子节点列表
        QDomNodeList nodeList = iomap_Doc.documentElement().childNodes();

        for(int i = 0; i < nodeList.size(); i++)
        {
            // 匹配IO类型
            if(nodeList.at(i).toElement().attribute("valueType").toInt() == IOValueTypeIn)
            {
                // 匹配逻辑值索引
                if(nodeList.at(i).toElement().attribute("logicValueIndex").toInt() == logicValueIndexIn)
                {
                    // 设置内容
                    iomap_Doc.documentElement().childNodes().at(i).firstChild().setNodeValue(QString::fromStdString(nameIn));
                    // 设置完成保存文件
                    IOMapFile.setFileName(configFilePath);
                    if(!IOMapFile.open(QFile::WriteOnly | QFile::Truncate))
                    {
                        returnFlag =-1;
                        IOMapFile.close();
                        return -1;
                    }

                    QTextStream fileTs(&IOMapFile);
                    fileTs.reset();
                    fileTs.setCodec("utf-8");
                    iomap_Doc.save(fileTs,4, QDomNode::EncodingFromTextStream);
                    IOMapFile.close();

                    qDebug() << "NodeType:" << IOValueTypeIn << "logicValueIndex:" << logicValueIndexIn << "Value:" << nodeList.at(i).firstChild().nodeValue();
                    returnFlag = 0;
                    break;
                }
                // 没有找到逻辑值索引
                else
                {
                    returnFlag =-1;
                    IOMapFile.close();
                }
            }
            // 没找到IO类型
            else
            {
                returnFlag =-1;
                IOMapFile.close();
            }
        }
    }
    else
    {
        returnFlag =-1;
        IOMapFile.close();
        return -1;
    }

    IOMapFile.close();
    // 防止程序异常关机时,数据丢失
    IOMapFile.flush();
    return returnFlag;
}


int RobotIo::readXmlConfig(  QString filepath )
{

    bool ok=openXml(filepath, QFile::ReadOnly|QFile::Text );
    if(!ok){
        qDebug()<<"ERROR: openXml :"<<ok<< filepath;
        return -1;
    }

    doCount =0 ;
    diCount =0 ;
    aoCount =0 ;
    aiCount =0 ;
    soCount =0 ;
    siCount =0 ;
    int  count=0;
    QDomNodeList devNodes = m_root.childNodes();
    int ncount=devNodes.size();
    allIoMap.resize( ncount ) ;
    for(int i=0;i<ncount;i++)
    {
        QDomNode devND =  devNodes.at(i);
        if( devND.nodeName().indexOf("#comment")>=0){
            continue;
        }

        IoMap tmpIomap;
        tmpIomap.nodeId=  devND.toElement().attribute("nodeId" ).toUInt();
        tmpIomap.valueType=  devND.toElement().attribute("valueType" ).toUInt();
        int __index = devND.toElement().attribute("logicValueIndex" ).toUInt();
        if( __index <1 ){
             tmpIomap.logicValueIndex=0;
             printf("WARN: iomap.xml: logicValueIndex<1 \n");
           // addMsg(ENUM_MSG_WARNING, "RobotIo", "RobotIo", 5001,  robotId ,   tmpIomap.nodeId,   tmpIomap.valueType, __index );
            closeXml();
            return -1;
        }else{
            tmpIomap.logicValueIndex= __index-1;
        }
       __index =  devND.toElement().attribute("deviceValueIndex" ).toUInt() ;
       if( __index <1 ){
           printf("WARN: iomap.xml: deviceValueIndex<1 \n");
           tmpIomap.deviceValueIndex=0;
          // addMsg(ENUM_MSG_WARNING, "RobotIo", "RobotIo", 5001,  robotId ,   tmpIomap.nodeId,   tmpIomap.valueType, __index );
           closeXml();
           return -2;
       }else{
           tmpIomap.deviceValueIndex= __index-1;
       }

        tmpIomap.devType = devND.toElement().attribute("devType" ).toUInt();
        tmpIomap.deviceProtocol = (E_DEVICE_PROTOCOL)devND.toElement().attribute("deviceProtocol" ).toUInt();
        tmpIomap.note = devND.firstChild().nodeValue();

        if(ok &&   tmpIomap.valueType != E_IoValueType_NULL )
        {
            allIoMap[ count ] = tmpIomap;
            count++;
        }
    }
    closeXml();

    initialIo(count);

    qDebug()<<"\n iomap.xml=="<< diCount<<doCount <<siCount<<soCount <<aiCount <<aoCount;

    isInitialOk=true;
    return true;
}

int RobotIo::initialIo( int itemCount  )
{
    allIoMap.resize( itemCount );
    for(int i=0;i<itemCount ;i++)
    {
        switch( allIoMap[i].valueType )
        {
        case    E_IoValueType_DI:
            ioDiMap.append( &allIoMap[i] );
            if( diCount<=allIoMap[i].logicValueIndex ){
                diCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        case       E_IoValueType_DO:
            ioDoMap.append( &allIoMap[i] );
            if( doCount<=allIoMap[i].logicValueIndex ){
                doCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        case      E_IoValueType_AI:
            ioAiMap.append( &allIoMap[i] );
            if( aiCount<=allIoMap[i].logicValueIndex ){
                aiCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        case     E_IoValueType_AO:
            ioAoMap.append( &allIoMap[i] );
            if( aoCount<=allIoMap[i].logicValueIndex ){
                aoCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        case         E_IoValueType_SI:
            ioSiMap.append( &allIoMap[i] );
            if( siCount<=allIoMap[i].logicValueIndex ){
                siCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        case      E_IoValueType_SO:
            ioSoMap.append( &allIoMap[i] );
            if( soCount<=allIoMap[i].logicValueIndex ){
                soCount=allIoMap[i].logicValueIndex+1;
            }
            break;
        }
    }

    return 1;
}

#endif
